package com.yy.micro.magic.utils;

import com.yy.micro.magic.core.config.Content;
import com.yy.micro.magic.core.model.RuleDescriptor;

import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;
import java.util.function.Function;
import java.util.stream.Collectors;

public class MapUtils {

    /**
     * 多层Map结构转换为一层Map结构，取最终叶子为Value，路径为连接为Key
     *
     * @param map
     * @return
     */
    public static Map<String, Object> mapToLevel(final Map<String, Object> map) {
        final Map<String, Object> target = new LinkedHashMap<String, Object>();
        traverse("", map, target);
        return target;
    }

    /**
     * 递归树的路径，生成唯一key
     *
     * @param parent
     * @param node
     * @return
     */
    public static String generateKay(final String parent, final String node) {
        return generateKay(parent, node, Content.KEY_PATH_SPERALTOR);
    }

    /**
     * 递归树的路径，生成唯一key
     *
     * @param parent
     *            父层路径
     * @param node
     *            子节点key
     * @param keySperator
     *            连接符
     * @return
     */
    public static String generateKay(final String parent, final String node, final String keySperator) {
        if (null == parent || parent.trim().length() < 1) {
            return node;
        }
        return parent + keySperator + node;
    }

    /**
     * 把Key分隔为路径数组
     *
     * @param key
     *            一层Map的Key
     * @return
     */
    public static String[] splitKey(final String key) {
        return splitKey(key, Content.KEY_PATH_SPERALTOR);
    }

    /**
     * 把Key分隔为路径数组
     *
     * @param key
     * @param keySperator
     *            路径分隔符
     * @return
     */
    public static String[] splitKey(final String key, final String keySperator) {
        return key.split(keySperator);
    }

    /**
     * 取分割后Key的最后一个
     *
     * @param key
     * @return
     */
    public static String getLastParameter(final String key) {
        final String[] keys = key.split(Content.KEY_PATH_SPERALTOR);
        return keys[keys.length - 1];
    }

    /**
     * 获取Kay的你路径
     *
     * @param key
     * @return
     */
    public static String getParentPath(final String key) {
        String parent = key;
        if (key.contains(Content.KEY_PATH_SPERALTOR)) {
            parent = key.substring(0, key.lastIndexOf(Content.KEY_PATH_SPERALTOR));
        }
        return parent;
    }

    /**
     * 不支持嵌套List，遍历Map，递归把多层Map结构转换为一层结构Map。遇到map中有"@properties"属性，则表示 到了叶子节点
     *
     * @param parentPath
     *            递归的路径
     * @param src
     *            源Map节点
     * @param target
     *            目标一层Map
     */
    @SuppressWarnings("unchecked")
    public static void traverse(final String parentPath, final Map<String, Object> src,
                                final Map<String, Object> target) {
        final Map<String, Object> map = sortOfPriorLeaf(src);
        if (map.containsKey(Content.MAPPING_INDENTIFIER)) {// 遇到
            // map中包含"@properties"属性，表示遍历到最外层节点，整
            // 个map作
            // 为最外层叶子节点
            map.remove(Content.MAPPING_INDENTIFIER);
            target.put(parentPath, map);
        } else {
            for (final Map.Entry<String, Object> entry : map.entrySet()) {
                final String key = entry.getKey();
                final Object value = entry.getValue();
                final String nkey = generateKay(parentPath, key);
                if (value instanceof Map) {// 子节点 是map，递归
                    traverse(nkey, (Map<String, Object>) value, target);
                } else if (value instanceof List) {// 子节点 是List，需要对List遍历
                    final List<?> list = (List<?>) value;
                    int idx=0;
                    for (int i = 0; i < list.size(); i++) {
                        final String lkey = generateKay(nkey, String.valueOf(idx),
                                Content.KEY_LIST_INDENTIFIER);// List下标参与，生成包含List的遍历路径
                        final Object v = list.get(i);
                        if (v instanceof Map) {// 递归map
                            final Map<String, Object> m = (Map<String, Object>) v;
                            if (null!=m && !m.isEmpty()) {
                                traverse(lkey, (Map<String, Object>) v, target);
                                idx+=1;
                            }
                        } else {// TODO 对List 中嵌套List支持不足
                            target.put(lkey, v);
                            idx+=1;
                        }
                    }
                } else {
                    target.put(nkey, value);
                }
            }
        }
    }

    /**
     * 保证叶子节点优先于树干节点
     *
     * @param map
     * @return
     */
    @SuppressWarnings("rawtypes")
    @Deprecated
    private static Map<String, Object> sortOfPriorLeaf(final Map<String, Object> map) {
        final Map<String, Object> result = new LinkedHashMap<String, Object>();
        map.forEach((k, v) -> {
            if (v instanceof Map && ((Map) v).containsKey(Content.MAPPING_INDENTIFIER)) {
                result.put(k, v);
            } else if (!(v instanceof Map || v instanceof List)) {
                result.put(k, v);
            }
        });
        map.forEach((k, v) -> {
            if (!result.containsKey(k)) {
                result.put(k, v);
            }
        });
        return result;
    }

    /**
     * 获取Map下某个节点的值，通常用于从请求数据中取出某一节点 的value
     *
     * @param key
     *            Map的访问路径，以{@link Content} 分隔
     * @param src
     *            源数据
     * @return
     */
    @Deprecated
    @SuppressWarnings({ "unchecked", "rawtypes" })
    public static Object getNodeOfMap(final String key, final Map<String, Object> src) {
        if (null == key || key.trim().length() < 1 || null == src) {
            return null;
        }
        final String[] keys = splitKey(key);
        Map<String, Object> map = src;
        Object value = null;
        for (final String k : keys) {// 循环遍历key路径
            if (k.contains(Content.KEY_LIST_INDENTIFIER)) {// 是否包含List的分隔符，如查有，需要对下标操作
                final String[] ks = splitKey(k, Content.KEY_LIST_INDENTIFIER);//
                final Object v = map.get(ks[0]);
                if (v instanceof List) {
                    value = ((List) v).get(Integer.valueOf(ks[1]));
                }
            } else {
                value = map.get(k);
            }
            if (value instanceof Map) {
                map = (Map<String, Object>) value;
            } else {
                if (!k.equalsIgnoreCase(keys[keys.length - 1])) {
                    value = null;// 遍历Key路径 时，未到最后一个节点且节点的值非Map类型，则返回null
                    break;
                }
            }
        }
        return value;
    }

//    /**
//     * Map转换为{@link MapMetadata}。从模板文件中解析出来的对象为Map，需要转换为指定的模板对象。
//     *
//     * @param map
//     * @return
//     */
//    @Deprecated
//    public static MapMetadata mapToMappingMetadata(final Map<String, Object> map) {
//        final String json = JsonUtils.toJson(map);
//        final MapMetadata metadata = JsonUtils.fromJson(json, MapMetadata.class);
//        return metadata;
//    }

    @Deprecated
    public static<T> T mapToTarget(final Object obj,Class<T> cls) {
        final String json = JsonUtils.toJson(obj);
        final T t = JsonUtils.fromJson(json, cls);
        return t;
    }

    /**
     * 遍历Map中的TreeMap，把TreeMap转换为List。在映射过程中，因对List操作时，不能保证下标的顺序，不宜用List存储List类型的值，用Treemap替代，映射完后，需要把结果集中的Treemap
     * 转换为List
     *
     * @param map
     * @return
     */
    public static Map<String, Object> treeMapToList(final Map<String, Object> map) {
        final Map<String, Object> target = new HashMap<String, Object>();
        traverseMap(map, target);
        return target;
    }

    /**
     * 遍历Map，把TreeMap转换为List
     *
     * @param src
     * @param target
     */
    @SuppressWarnings("unchecked")
    private static void traverseMap(final Map<String, Object> src, final Map<String, Object> target) {
        for (final Map.Entry<String, Object> entry : src.entrySet()) {
            final Object value = entry.getValue();
            final String key = entry.getKey();
            if (value instanceof TreeMap) {
                final TreeMap<String, Object> m = (TreeMap<String, Object>) value;
                final List<String> s = m.keySet().stream()
                        .sorted((k1, k2) -> Integer.valueOf(k1) > Integer.valueOf(k2) ? 1 : -1)
                        .collect(Collectors.toList());// 对Treemap的key进行排序
                final List<Object> list = new ArrayList<Object>();
                s.stream().forEach(k -> list.add(m.get(k)));// 按排序后的key取出value，还原Treemap中values的顺序
                // final List<Object> list = new ArrayList<Object>(mm.values());
                final List<Object> tlist = new ArrayList<Object>();
                target.put(key, tlist);
                traverseList(list, tlist);// 遍历List
            } else if (value instanceof Map) {// 遍历Map
                final Map<String, Object> tmap = new HashMap<String, Object>();
                target.put(key, tmap);
                traverseMap((Map<String, Object>) value, tmap);
            } else {
                target.put(key, value);
            }
        }

    }

    /**
     * 处理treemap
     *
     * @param src
     * @param tlist
     */
    @SuppressWarnings("unchecked")
    private static void traverseList(final List<Object> src, final List<Object> tlist) {
        for (final Object object : src) {
            if (object instanceof TreeMap) {
                final TreeMap<String, Object> m = (TreeMap<String, Object>) object;
                final List<String> s = m.keySet().stream()
                        .sorted((k1, k2) -> Integer.valueOf(k1) > Integer.valueOf(k2) ? 1 : -1)
                        .collect(Collectors.toList());// 对Treemap的key进行排序
                final List<Object> list = new ArrayList<Object>();
                s.stream().forEach(k -> list.add(m.get(k)));// 按排序后的key取出value，还原Treemap中values的顺序
                // final List<Object> list = new ArrayList<Object>(m.values());
                final List<Object> tlist2 = new ArrayList<Object>();
                tlist.add(tlist2);
                traverseList(list, tlist2);
            } else if (object instanceof Map) {
                final Map<String, Object> tmap = new HashMap<String, Object>();
                tlist.add(tmap);
                traverseMap((Map<String, Object>) object, tmap);
            } else {
                tlist.add(object);
            }
        }
    }

    /**
     * 遍历map，并把所有的KEY改为大写
     *
     * @param map
     * @return
     */
    @Deprecated
    public static Map<String, Object> keyToUpper(final Map<String, Object> map) {
        final Function<String, String> func = (s) -> s.toUpperCase();
        return keyConver(map, func);
    }

    /**
     * Key转换，大小写
     *
     * @param map
     * @param func
     *            key处理表达式
     * @return
     */
    @Deprecated
    public static <S> Map<String, Object> keyConver(final Map<String, Object> map,
                                                    final Function<String, String> func) {
        final Map<String, Object> result = new HashMap<String, Object>();
        traverse(map, result, func);
        return result;
    }

    /**
     * 遍历Map，把key节点 按func处理
     *
     * @param map
     * @param result
     * @param func
     */
    @SuppressWarnings("unchecked")
    private static void traverse(final Map<String, Object> map, final Map<String, Object> result,
                                 final Function<String, String> func) {
        for (final Map.Entry<String, Object> entry : map.entrySet()) {
            final String key = func.apply(entry.getKey());// 处理吸节点，func为一个lambda表达式
            final Object value = entry.getValue();
            if (value instanceof Map) {// Map节点
                final Map<String, Object> rs = new HashMap<String, Object>();
                result.put(key, rs);
                traverse((Map<String, Object>) value, rs, func);
            } else if (value instanceof List) {// List节点
                final List<Object> list = (List<Object>) value;
                final List<Object> rlist = new ArrayList<Object>();
                result.put(key, rlist);
                for (final Object object : list) {
                    if (object instanceof Map) {
                        final Map<String, Object> rs = new HashMap<String, Object>();
                        rlist.add(rs);
                        traverse((Map<String, Object>) object, rs, func);
                    } else {
                        rlist.add(object);
                    }
                }
            } else {
                result.put(key, value);
            }
        }
    }

    /**
     * <p>
     * Description:将对象按属性插入到map中。JavaBean转换为Map，
     * </p>
     *
     * @param object
     * @return
     */
    @Deprecated
    public static Map<String, Object> objToMap(final Object object) {
        final Map<String, Object> map = new HashMap<>();
        final Field[] fields = object.getClass().getDeclaredFields();
        for (final Field field : fields) {
            final String firstLetter = field.getName().substring(0, 1).toUpperCase();
            final String name = firstLetter + field.getName().substring(1);
            final Object value = getValueByFieldName(name, object);
            if (value != null) {
                map.put(field.getName(), value);
            }
        }
        return map;
    }

    /**
     * 反射的到各个属性的值
     */
    @Deprecated
    private static Object getValueByFieldName(final String fieldName, final Object obj) {
        final String getter = "get" + fieldName;
        try {
            final Method method = obj.getClass().getMethod(getter, new Class[] {});
            final Object value = method.invoke(obj, new Object[] {});
            return value;
        } catch (final Exception e) {
            // logger.info("",e);
        }
        return null;
    }

    /**
     * 根据条件（正则）过滤出符合条件 的模板
     *
     * @param templates
     *            映射模板
     * @param pattern
     *            过滤条件,正则表达式eg:{@code "[\\w]*icyLobList-[\\d]+#[\\w]*";}
     * @return
     */
    @Deprecated
    public static Map<String, RuleDescriptor> filterTemplates(final Map<String, RuleDescriptor> templates,
                                                              final String pattern) {
        final Map<String, RuleDescriptor> result = new HashMap<String, RuleDescriptor>();
        templates.forEach((k, v) -> {
            if (k.matches(pattern)) {
                result.put(k, v);
            }
        });
        return result;
    }

    public static int NOT_OBJECT_NULL = 1;// 对象值为null
    public static int NOT_LIST_MAP_EMPTY = 1 << 1;// List为empty或是null
    public static int FIRST_UPPER = 1 << 2;// 首字母大写
    public static int ALL_UPPER = 1 << 3;// 全大写
    public static int ALL_LOWER = 1 << 4;// 全小写

    /**
     * 处理对象中的内容，把空list和null对象清理。
     *
     * @param t
     * @return
     */
    public static <T> T screenObject(final T t) {
        return screenObject(t, NOT_LIST_MAP_EMPTY | NOT_OBJECT_NULL);
    }

    @SuppressWarnings("unchecked")
    public static <T> T screenObject(final T t, final int mode) {
        return (T) traverseObject(t, mode);
    }

    /**
     * 遍历Map，筛选出甩的value不为空的节点
     *
     * @param map
     * @return
     */
    private static Map<String, Object> traverseMap(final Map<String, Object> map, final int mode) {
        final Map<String, Object> result = new HashMap<String, Object>();
        for (final Map.Entry<String, Object> entry : map.entrySet()) {
            final Object value = entry.getValue();
            final Object rs = traverseObject(value, mode);
            if (NOT_OBJECT_NULL == (NOT_OBJECT_NULL & mode)) {
                if (null != rs) {
                    result.put(getOutKay(entry.getKey(), mode), rs);
                }
            } else {
                result.put(getOutKay(entry.getKey(), mode), rs);
            }
        }
        return result;
    }

    /**
     * 输出key的模式，首字母大写，全小写，全大写，保持不变
     *
     * @param key
     * @param mode
     * @return
     */
    private static String getOutKay(final String key, final int mode) {
        if (FIRST_UPPER == (FIRST_UPPER & mode)) {
            return JsonUtils.firstUpperCase(key);
        } else if (ALL_UPPER == (ALL_UPPER & mode)) {
            return key.toUpperCase();
        } else if (ALL_LOWER == (ALL_LOWER & mode)) {
            return key.toLowerCase();
        } else {
            return key;
        }
    }

    /**
     * 遍历对象，特别处理Map和List，遇到这种集合，需要遍历其所有元素。采用后续遍历方式，便于清理list为empty的内容
     *
     * @param obj
     * @param mode
     * @return
     */
    @SuppressWarnings("unchecked")
    private static Object traverseObject(final Object obj, final int mode) {
        Object result = null;
        if (obj instanceof Map) {// 遍历Map中所有元素，筛选出所有value不为null的元素
            final Map<String, Object> r = traverseMap((Map<String, Object>) obj, mode);
            if (NOT_LIST_MAP_EMPTY == (NOT_LIST_MAP_EMPTY & mode)) {
                if (null != r && !r.isEmpty()) {// 如查后的Map为null或是empty，则不放入最终结果集中
                    result = r;
                }
            } else {
                result = r;
            }
        } else if (obj instanceof List) {// 同Map
            final List<Object> l = traverseList((List<Object>) obj, mode);
            if (NOT_LIST_MAP_EMPTY == (NOT_LIST_MAP_EMPTY & mode)) {
                if (null != l && !l.isEmpty()) {
                    result = l;
                }
            } else {
                result = l;
            }
        } else {
            if (NOT_OBJECT_NULL == (NOT_OBJECT_NULL & mode)) {
                if (null != obj) {
                    result = obj;
                }
            } else {
                result = obj;
            }
        }
        return result;
    }

    /**
     * 遍历List，返回List中所有不为null的元素
     *
     * @param list
     * @return
     */
    private static List<Object> traverseList(final List<Object> list, final int mode) {
        final List<Object> rl = new ArrayList<Object>();
        for (final Object value : list) {
            final Object rs = traverseObject(value, mode);
            if (null != rs) {
                rl.add(rs);
            }
        }
        return rl;
    }
}
